package com.xlh.support.experimentshare.websocket;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Multimaps;
import com.xlh.support.experimentshare.domain.ShareUser;
import com.xlh.util.SpringContextUtil;
import com.xlh.websocket.GetHttpSessionConfigurator;
import com.xlh.websocket.message.Message;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * 分享桌面页面建立的websocket，用于关闭分享、调整分辨率、切换窗口
 *
 * @author cheer
 */
@ServerEndpoint(value = "/ws/close-share/{userId}/{chapterId}", configurator = GetHttpSessionConfigurator.class)
@Component
@Slf4j
public class CloseShareWebsocket {

    private static ObjectMapper objectMapper = SpringContextUtil.getBean(ObjectMapper.class);

    private static ListMultimap<ShareUser, CloseShareWebsocket> connectionMap = Multimaps.synchronizedListMultimap(ArrayListMultimap.create());

    private Session session;

    /**
     * 分享用户Id
     */
    private Long shareUserId;

    /**
     * 分享章节Id
     */
    private Long shareChapterId;

    /**
     * 接受分享用户Id
     */
    private Long sharedUserId;

    @OnOpen
    public void onOpen(Session session, @PathParam("userId") Long userId, @PathParam("chapterId") Long chapterId,
                       EndpointConfig config) {
        this.session = session;
        this.shareUserId = userId;
        this.shareChapterId = chapterId;
        this.sharedUserId = (Long) config.getUserProperties().get("userId");
        ShareUser shareUser = ShareUser.builder()
                .userId(userId)
                .chapterId(chapterId)
                .build();
        connectionMap.put(shareUser, this);
    }

    @OnClose
    public void onClose() {
        ShareUser shareUser = ShareUser.builder()
                .userId(shareUserId)
                .chapterId(shareChapterId)
                .build();
        connectionMap.remove(shareUser, this);
    }

    @OnMessage
    public void onMessage(String jsonStr, Session session) {
        // 暂时不需要实现该方法
    }

    @OnError
    public void onError(Session session, Throwable error) {
        // 暂时不需要实现该方法
    }

    /**
     * 发送消息
     *
     * @param shareUser 分享用户
     * @param message   消息内容
     */
    public static void sendMessage(ShareUser shareUser, Message message) {
        try {
            List<CloseShareWebsocket> closeShareWebsockets = new ArrayList<>(connectionMap.get(shareUser));
            if (CollectionUtils.isNotEmpty(closeShareWebsockets)) {
                String sendMessage = objectMapper.writeValueAsString(message);
                for (CloseShareWebsocket closeShareWebsocket : closeShareWebsockets) {
                    try {
                        closeShareWebsocket.session.getBasicRemote().sendText(sendMessage);
                    } catch (IOException e) {
                        log.warn("websocket send message exception", e);
                    }
                }
            }
        } catch (JsonProcessingException e) {
            log.error("json process exception", e);
        }
    }

    /**
     * 发送消息
     *
     * @param shareUser     分享用户
     * @param message       消息内容
     * @param sharedUserIds 接受分享用户的Id
     */
    public static void sendMessage(ShareUser shareUser, Message message, Set<Long> sharedUserIds) {
        try {
            List<CloseShareWebsocket> closeShareWebsockets = new ArrayList<>(connectionMap.get(shareUser));
            if (CollectionUtils.isNotEmpty(closeShareWebsockets)) {
                String sendMessage = objectMapper.writeValueAsString(message);
                for (CloseShareWebsocket closeShareWebsocket : closeShareWebsockets) {
                    if (sharedUserIds.contains(closeShareWebsocket.sharedUserId)) {
                        try {
                            closeShareWebsocket.session.getBasicRemote().sendText(sendMessage);
                        } catch (IOException e) {
                            log.warn("websocket send message exception", e);
                        }
                    }
                }
            }
        } catch (JsonProcessingException e) {
            log.error("json process exception", e);
        }
    }
}
